home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-09-03 | 8.5 KB | 261 lines | [TEXT/CWIE] |
- // ===========================================================================
- // UDebugging.h ©1994 Metrowerks Inc. All rights reserved.
- // ===========================================================================
- //
- // Debugging macros and functions
- //
- // These debugging macros let you control what happens when you
- // throw an exception or raise a signal. By defining certain
- // compiler symbols and global variables, you can display an alert,
- // break into the low-level debugger, or break into the source-level
- // debugger before an exception is thrown or when a signal is raised.
- //
- //
- // Throw options
- //
- // The macros for throwing exceptions defined in UException.h all
- // eventually invoke the Throw_ macro. For example,
- // ThrowIfOSErr_(err) is defined as if ((err) != 0) Throw_(err)
- //
- // This header defines the Throw_ macro. The definition used depends
- // on the setting the the Debug_Throw compiler symbol. If you
- // don't #define Debug_Throw, Throw_ is defined to just call the
- // Throw() function. This creates no extra runtime overhead; the
- // preprocessor does all the work.
- //
- // However, if you #define Debug_Throw, the Throw_ macro is defined to
- // check the global variable gDebugThrow to decide what to do before
- // eventually calling Throw(). The value of gDebugThrow may be:
- //
- // debugAction_Nothing do nothing
- // debugAction_Alert display an Alert box
- // debugAction_LowLevelDebugger break into MacsBug
- // debugAction_SourceDebugger break into CodeWarrior Debugger
- //
- // The Alert box displays the Exception code, as well as the file
- // name and line number where the Throw_ was made.
- //
- // For the low-level debugger, the Exception code is displayed as a
- // string. In MacsBug, the console will display two lines:
- // User Break at <Routine> + <Offset>
- // <Exception Code>
- //
- // For the source-level debugger, execution will stop with the
- // "arrow" pointing to line containing the Throw instruction. The
- // Exception code is not displayed. You can check the display of
- // variable values in the source debugger for that information.
- //
- // If you aren't running under the source debugger,
- // debugAction_SourceDebugger will break into the low-level debugger
- // on the PowerPC, but may (will?) crash on the 68K.
- //
- // If you don't have a low-level debugger installed, your program will
- // crash (unimplemented trap) if it tries to break into the
- // low-level debugger.
- //
- //
- // Signal options
- //
- // This header also defines macros for raising Signals. The
- // SignalPStr_(pstr) macro takes a Pascal string argument. The
- // string can be a literal (in double quotes beginning with \p)
- // or a StringPtr (and its variants such as Str255) variable.
- //
- // The SignalCStr_(cstr) macro takes a literal C string argument.
- // The string must be a literal (text within double quotes) and
- // can't be a char*. Because the underlying Toolbox routines take
- // Pascal strings, the SignalPStr_ macro is more efficient. So you
- // should always use SignalPStr_ when specifying string literals.
- // The SignalCStr_ macro is used internally because the C preprocessor
- // generates C strings for the # operator in macros.
- //
- // The SignalIf_(test) and SignalIfNot_(test) macros each take a
- // boolean condition as an argument, and raise a signal depending
- // on whether the condition is true or false.
- //
- // If you don't #define Debug_Signal, the Signal macros do nothing.
- // There is no runtime overhead; the preprocessor substitutes
- // white space for the macros.
- //
- // If you #define Debug_Signal, then the macros are defined to check
- // the global variable gDebugSignal to decide what to do. The options
- // are the same as those describe above for gDebugThrow.
- //
- //
- // Usage Notes
- //
- // These debugging utilities do not require PowerPlant. All you need
- // are the UDebugging and UException header (.h) and source (.cp)
- // files (and, of course, the Toolbox and C++ runtime libraries).
- //
- // To define debugging options for an entire project, specify a
- // custom header as the Prefix File (in the Language Preferences).
- // In this custom header, you should #include your precompiled
- // header (if you use one), for example:
- //
- // #include <MacHeaders68K>
- //
- // Then include the following lines:
- //
- // #define Debug_Throw
- // #define Debug_Signal
- // #include <UDebugging.h>
- // #include <UException.h>
- //
- // Then add any additional declarations that you wish to make.
- //
- // Comment out the #define's of Debug_Throw and/or Debug_Signal
- // when you wish to turn off those features.
- //
- // By default, gDebugThrow and gDebugSignal are set to
- // debugAction_Nothing. These are runtime global variables, so
- // you can set their values at any point in the program. Usually,
- // you will set their values at the beginning of your main program,
- // but you can set them in other places if you want to use different
- // options in different sections of code.
- //
- // Another technique is to change the values of gDebugThrow and/or
- // gDebugSignal from the source-level debugger when you are stopped
- // at a breakpoint. This is the recommended way to use the
- // debugAction_SourceDebugger option. As noted above, using that
- // option when not running under the source debugger can cause a
- // crash on the 68K.
-
-
- #pragma once
-
- #ifndef __TEXTUTILS__
- #include <TextUtils.h>
- #endif
-
- #ifndef __STRINGS__
- #include <Strings.h>
- #endif
-
-
- // • Functions for displaying Alert boxes
-
- class UDebugging {
- public:
- static void AlertThrowAt(unsigned char *inError, unsigned char *inFile,
- long inLine);
- static void AlertSignalAt(unsigned char *inTestStr,
- unsigned char *inFile, long inLine);
- };
-
-
- // • Macros for breaking into the low-level and source debuggers
- // For arcane reasons, the Toolbox routines SysBreak() and Debugger()
- // work oppositely on the PowerPC and 68K.
-
- // You can use these macros to break to the low-level and source
- // debuggers, with or without displaying a (Pascal) string.
-
- #ifdef powerc
-
- #define BreakToLowLevelDebugger_() SysBreak()
- #define BreakStrToLowLevelDebugger_(s) SysBreakStr(s)
- #define BreakToSourceDebugger_() Debugger()
- #define BreakStrToSourceDebugger_(s) DebugStr(s)
-
- #else // 68K
-
- #define BreakToLowLevelDebugger_() Debugger()
- #define BreakStrToLowLevelDebugger_(s) DebugStr(s)
- #define BreakToSourceDebugger_() SysBreak()
- #define BreakStrToSourceDebugger_(s) SysBreakStr(s)
-
- #endif
-
-
- // • Debugging Actions
-
- typedef enum {
- debugAction_Nothing = 0,
- debugAction_Alert = 1,
- debugAction_LowLevelDebugger = 2,
- debugAction_SourceDebugger = 3
- } EDebugAction;
-
- extern EDebugAction gDebugThrow;
- extern EDebugAction gDebugSignal;
-
-
- // • Throw Debugging
-
- #ifdef Debug_Throw
-
- #define SetDebugThrow_(inAction) gDebugThrow = inAction
-
- #define Throw_(err) \
- do { \
- unsigned char errStr[16]; \
- ::NumToString(err, errStr); \
- if (gDebugThrow == debugAction_Alert) { \
- unsigned char fileStr[] = __FILE__; \
- c2pstr((char*) fileStr); \
- UDebugging::AlertThrowAt(errStr, fileStr, __LINE__); \
- } else if (gDebugThrow == debugAction_LowLevelDebugger) { \
- BreakStrToLowLevelDebugger_(errStr); \
- } else if (gDebugThrow == debugAction_SourceDebugger) { \
- BreakToSourceDebugger_(); \
- } \
- throw (ExceptionCode)(err); \
- } while (false)
-
- #else
-
- #define SetDebugThrow_(inAction)
-
- #define Throw_(err) throw (ExceptionCode)(err)
-
- #endif // Debug_Throw
-
-
- // • Signal Debugging
-
- #ifdef Debug_Signal
-
- #define SetDebugSignal_(inAction) gDebugSignal = inAction
-
- #define SignalPStr_(pstr) \
- do { \
- if (gDebugSignal == debugAction_Alert) { \
- unsigned char fileStr[] = __FILE__; \
- c2pstr((char*) fileStr); \
- UDebugging::AlertSignalAt(pstr, fileStr, __LINE__); \
- } else if (gDebugSignal == debugAction_LowLevelDebugger) { \
- BreakStrToLowLevelDebugger_(pstr); \
- } else if (gDebugSignal == debugAction_SourceDebugger) { \
- BreakToSourceDebugger_(); \
- } \
- } while (false)
-
- #define SignalCStr_(cstr) \
- do { \
- unsigned char sigStr[] = cstr; \
- c2pstr((char*) sigStr); \
- SignalPStr_(sigStr); \
- } while (false)
-
- #define SignalIf_(test) \
- do { \
- if (test) SignalCStr_(#test); \
- } while (false)
-
- #define SignalIfNot_(test) SignalIf_(!(test))
-
-
- #else
-
- #define SetDebugSignal_(inAction)
-
- #define SignalPStr_(pstr)
- #define SignalCStr_(cstr)
- #define SignalIf_(test)
- #define SignalIfNot_(test)
-
- #endif // Debug_Signal
-
- #define Assert_(test) SignalIfNot_(test)
-